/*
 * Toedo
 * Copyright (C) 2009-2010 J. Devauchelle and contributors.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 3 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

package org.toedo.gui.views;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.UUID;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.forms.widgets.Section;
import org.toedo.controllers.DataController;
import org.toedo.controllers.events.EventConstants;
import org.toedo.controllers.events.EventController;
import org.toedo.controllers.ui.MenuController;
import org.toedo.gui.actions.ChangeTaskPriorityAction;
import org.toedo.gui.actions.ChangeTaskStatusAction;
import org.toedo.gui.actions.DeleteTaskAction;
import org.toedo.gui.actions.RenameBaseNoteAction;
import org.toedo.gui.dialogs.AttachmentsManagementDialog;
import org.toedo.gui.dialogs.DateSelectorDialog;
import org.toedo.gui.dialogs.TagsManagementDialog;
import org.toedo.gui.listeners.PartListener2Adapter;
import org.toedo.gui.translations.Messages;
import org.toedo.model.BaseNote;
import org.toedo.model.Task;
import org.toedo.model.Task.TaskStatus;
import org.toedo.utils.ApplicationUtils;
import org.toedo.utils.DateUtils;
import org.toedo.Activator;

public class TaskView extends BaseNoteViewPart implements PropertyChangeListener {
	
	public static final String ID = "toedo-core.TaskView"; //$NON-NLS-1$
	
	private Task mTask = null;
	
	private Label mModificationDateValueLabel;
	
	private Hyperlink mChangeStartDate;
	private Label mStartDateLabel;
	private Hyperlink mChangeDueDate;
	private Label mDueDateLabel;
	
	private Hyperlink mChangePriority;
	private Label mPriorityLabel;
	
	private Hyperlink mChangeTags;
	
	private Action mManageAttachmentsAction;
	private Action mRenameAction;
	private Action mChangeTaskStatusAction;
	private Action mDeleteAction;
	
	private Image mStatusClosed;
	private Image mStatusOk;
	private Image mStatusLate;
	private Image mStatusUrgent;
	
	public TaskView() {
		super();
		Activator.getDefault();
		mStatusOk = Activator.getImageDescriptor("/icons/status-ok-16.png").createImage(); //$NON-NLS-1$
		mStatusClosed = Activator.getImageDescriptor("/icons/status-closed-16.png").createImage(); //$NON-NLS-1$
		mStatusLate = Activator.getImageDescriptor("/icons/status-late-16.png").createImage(); //$NON-NLS-1$
		mStatusUrgent = Activator.getImageDescriptor("/icons/status-urgent-16.png").createImage(); //$NON-NLS-1$
		
		buildActions();
	}
	
	private void buildActions() {
		mManageAttachmentsAction = new Action(Messages.TaskView_ManageAttachmentActionToolTip) {
			public void run() {
				new AttachmentsManagementDialog(mParent.getShell(), mTask).open();
			}
		};
		mManageAttachmentsAction.setImageDescriptor(Activator.getImageDescriptor("/icons/attachement-16.png")); //$NON-NLS-1$
		
		mRenameAction = new Action(Messages.TaskView_RenameAction) {
			public void run() {
				new RenameBaseNoteAction(mParent.getShell(), mTask).run();
			}
		};
		mRenameAction.setImageDescriptor(Activator.getImageDescriptor("/icons/rename-16.png")); //$NON-NLS-1$
		
		mChangeTaskStatusAction = new Action(Messages.TaskView_CloseAction) {
			public void run() {
				new ChangeTaskStatusAction(mTask).run();
			}
		};
		mChangeTaskStatusAction.setImageDescriptor(Activator.getImageDescriptor("/icons/change-status-16.png")); //$NON-NLS-1$
		
		mDeleteAction = new Action(Messages.TaskView_DeleteAction) {
			public void run() {
				new DeleteTaskAction(mParent.getShell(), mTask).run();
			}
		};
		mDeleteAction.setImageDescriptor(Activator.getImageDescriptor("/icons/delete-16.png")); //$NON-NLS-1$
	}

	@Override
	public void createPartControl(Composite parent) {
		mParent = parent;
		mTask = DataController.getInstance().getProject().getTaskById(UUID.fromString(this.getViewSite().getSecondaryId()));
		
		if (mTask != null) {				
			mTask.setViewOpen(true);
			
			buildFormHeader(mTask, mStatusOk);
			
			mFocusListener = new PartListener2Adapter() {				
				@Override
				public void partDeactivated(IWorkbenchPartReference partRef) {
					if (partRef.getPart(false) == TaskView.this) {
						MenuController.getInstance().setSwitchEditActionEnabled(false);
					}
				}
				
				@Override
				public void partActivated(IWorkbenchPartReference partRef) {
					if (partRef.getPart(false) == TaskView.this) {
						MenuController.getInstance().setSwitchEditActionEnabled(true);
					}
				}
			};
			this.getViewSite().getPage().addPartListener(mFocusListener);
			
			mForm.getToolBarManager().add(mManageAttachmentsAction);
			mForm.getToolBarManager().add(mRenameAction);
			mForm.getToolBarManager().add(new Separator());
			mForm.getToolBarManager().add(mChangeTaskStatusAction);
			mForm.getToolBarManager().add(new Separator());
			mForm.getToolBarManager().add(mDeleteAction);
			mForm.getToolBarManager().update(true);					
			
			buildContentSection(mTask);
			
			Section detailsSection = mToolkit.createSection(mForm.getBody(), 
					 Section.TITLE_BAR | Section.TWISTIE | Section.EXPANDED);
			detailsSection.setText(Messages.TaskView_DetailsSectionTitle);
			GridData gd = new GridData(SWT.FILL, SWT.FILL, true, false);
			detailsSection.setLayoutData(gd);
			
			Composite dateComposite = mToolkit.createComposite(detailsSection);
			dateComposite.setLayout(new GridLayout(4, false));
			
			mToolkit.createLabel(dateComposite, "Modification date:");
			mModificationDateValueLabel = mToolkit.createLabel(dateComposite, null);
			mModificationDateValueLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
			updateModificationDate();
			
			mToolkit.createLabel(dateComposite, Messages.NoteView_CreationDate);
			Label creationDateValueLabel = mToolkit.createLabel(dateComposite, null);
			creationDateValueLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
			creationDateValueLabel.setText(DateUtils.dateTimeToDisplayString(mTask.getCreationDate()));
			
			mChangeStartDate = mToolkit.createHyperlink(dateComposite, Messages.TaskView_StartDateLabel, SWT.NONE);			
		 	mChangeStartDate.addHyperlinkListener(new HyperlinkAdapter() {
				@Override
				public void linkActivated(HyperlinkEvent e) {
					DateSelectorDialog dialog =  new DateSelectorDialog(mParent.getShell(), mTask, mTask.getStartDate());					
					int result = dialog.open();
					if (result == Dialog.OK) {
						DataController.getInstance().getProject().setTaskStartDate(mTask, dialog.getSelectedDate());									
					}
				}
		 	});
		 	mStartDateLabel = mToolkit.createLabel(dateComposite, "StartDate"); //$NON-NLS-1$
		 	mStartDateLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
			
			mChangeDueDate = mToolkit.createHyperlink(dateComposite, Messages.TaskView_DueDateLabel, SWT.NONE);			
			mChangeDueDate.addHyperlinkListener(new HyperlinkAdapter(){
				@Override
				public void linkActivated(HyperlinkEvent e) {
					DateSelectorDialog dialog =  new DateSelectorDialog(mParent.getShell(), mTask, mTask.getDueDate());					
					int result = dialog.open();
					if (result == Dialog.OK) {
						DataController.getInstance().getProject().setTaskDueDate(mTask, dialog.getSelectedDate());										
					}
				}
			});
			mDueDateLabel = mToolkit.createLabel(dateComposite, "DueDate", SWT.NONE); //$NON-NLS-1$
			mDueDateLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
			
			mChangePriority = mToolkit.createHyperlink(dateComposite, Messages.TaskView_PriorityLabel, SWT.NONE);
			mChangePriority.addHyperlinkListener(new HyperlinkAdapter(){
				@Override
				public void linkActivated(HyperlinkEvent e) {
					new ChangeTaskPriorityAction(mParent.getShell(), mTask).run();
				}
			});
			mPriorityLabel = mToolkit.createLabel(dateComposite, null);
			mPriorityLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
			
			mChangeTags = mToolkit.createHyperlink(dateComposite, Messages.TaskView_TagsLabel, SWT.NONE);
			mChangeTags.addHyperlinkListener(new HyperlinkAdapter(){
				@Override
				public void linkActivated(HyperlinkEvent e) {
					TagsManagementDialog dialog =  new TagsManagementDialog(mParent.getShell(), mTask);					
					dialog.open();
				}
			});
			mTagsList = mToolkit.createLabel(dateComposite, null);
			mTagsList.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
			
			detailsSection.setClient(dateComposite);
			
			buildAttachmentSection(mTask);
			
			updateDisplay();
			
			EventController.getInstance().addGeneralEventsListener(this);
		}
	}
	
	@Override
	public void switchEditMode() {
		switchEditMode(mTask);
	}
	
	@Override
	protected String getEmptyMessage() {
		return String.format(Messages.BaseNoteViewPart_EmptyMessage, "task");
	}
	
	private Image getImage() {
		switch (mTask.getStatus()) {
		case EnOpen : if (mTask.isLate()) {
			return mStatusLate;
		} if (mTask.isUrgent()) {
			return mStatusUrgent;
		} else {
			return mStatusOk;
		}
		case EnClosed : return mStatusClosed;
		default : return mStatusOk;
		}
	}
	
	private void updateModificationDate() {
		mModificationDateValueLabel.setText(DateUtils.dateTimeToDisplayString(mTask.getModificationDate()));
	}
	
	private void updateDisplay() {
		super.updateDisplay(mTask);
		
		setTitleImage(getImage());
		mForm.setImage(getImage());
		
		mStartDateLabel.setText(DateUtils.dateToDisplayString(mTask.getStartDate()));
		
		String dueDateMessage;
		int delta = mTask.getDeltaInDays();
		if (delta >= 0) {
			dueDateMessage = String.format(Messages.TaskView_DueDateLabelOnTime, DateUtils.dateToDisplayString(mTask.getDueDate()), Integer.toString(mTask.getDeltaInDays()));
		} else {
			dueDateMessage = String.format(Messages.TaskView_DueDateLabelLate, DateUtils.dateToDisplayString(mTask.getDueDate()), Integer.toString(- mTask.getDeltaInDays()));
		}
		
		mDueDateLabel.setText(dueDateMessage);
		
		mPriorityLabel.setText(Integer.toString(mTask.getPriority()));
		
		mChangeTaskStatusAction.setText(mTask.getStatus() == TaskStatus.EnClosed ? Messages.TaskView_ReopenAction : Messages.TaskView_CloseAction);
		mForm.getToolBarManager().update(true);
		
		mForm.layout(true);
	}

	@Override
	public void propertyChange(PropertyChangeEvent arg0) {
		class AttachmentsRefresher implements Runnable {
			public void run() {
				updateAttachmentDisplay(mTask);
			}
		}
		class TagsRefresher implements Runnable {
			public void run() {
				updateTagsList(mTask);
			}
		}
		class ModificationDateRefresher implements Runnable {
			public void run() {
				updateModificationDate();
			}
		}
		class ViewerRefresher implements Runnable {
			public void run() {
				updateDisplay();
			}
		}
		
		if ((arg0.getPropertyName().equals(EventConstants.EVT_MODIFY_TASK)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_RENAME_BASENOTE))) {
			
			if (((BaseNote) arg0.getNewValue()).getId().equals(mTask.getId())) {
				Display.getDefault().asyncExec(new ViewerRefresher());
				setDirty(true);
			}
		} else if (arg0.getPropertyName().equals(EventConstants.EVT_DELETE_TASK)) {
			
			if (((Task) arg0.getNewValue()).getId().equals(mTask.getId())) {
				ApplicationUtils.closeViewByID(TaskView.ID, this.getViewSite().getSecondaryId());				
			}
			
		} else if (arg0.getPropertyName().equals(EventConstants.EVT_PROJECT_PROPERTIES_CHANGE)) {
			
			if ((((String) arg0.getNewValue()).equals(EventConstants.EVT_PROJECT_PROPERTIES_DISPLAY_CSS_CHANGE)) ||
					(((String) arg0.getNewValue()).equals(EventConstants.EVT_PROJECT_PROPERTIES_MARKUP_CHANGE))) {
				Display.getDefault().asyncExec(new ViewerRefresher());
			}
			
		} else if ((arg0.getPropertyName().equals(EventConstants.EVT_ADD_ATTACHMENT)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_REMOVE_ATTACHMENT)) ||
				(arg0.getPropertyName().equals(EventConstants.EVT_MODIFY_ATTACHMENT))) {
			
			Display.getDefault().asyncExec(new AttachmentsRefresher());
		
		} else if (arg0.getPropertyName().equals(EventConstants.EVT_BASENOTE_TAG_CHANGE)) {
			
			Display.getDefault().asyncExec(new TagsRefresher());
			
		} else if (arg0.getPropertyName().equals(EventConstants.EVT_SAVE)) {
			Display.getDefault().asyncExec(new ModificationDateRefresher());
			setDirty(false);
		}
	}

	public void dispose() {
		EventController.getInstance().removeGeneralEventsListener(this);
		
		mTask.setViewOpen(false);
		
		mStatusOk.dispose();
		mStatusClosed.dispose();
		mStatusLate.dispose();
		mStatusUrgent.dispose();
		
		super.dispose();
	}

	@Override
	public void setFocus() { }
	
}
